#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
轻量级语法验证器（A层）
在每个文件混淆后立即进行基础语法检查
无外部依赖，纯Python实现
"""

import re
from typing import Dict, List, Tuple, Optional
from dataclasses import dataclass
from ..utils_module.language_utils import language_to_extensions

@dataclass
class ValidationResult:
    """验证结果"""
    is_valid: bool
    errors: List[Dict[str, any]]
    warnings: List[Dict[str, any]]
    file_path: str
    
    def add_error(self, message: str, line: int = 0, column: int = 0):
        self.errors.append({
            'message': message,
            'line': line,
            'column': column,
            'severity': 'error'
        })
        self.is_valid = False
    
    def add_warning(self, message: str, line: int = 0, column: int = 0):
        self.warnings.append({
            'message': message,
            'line': line,
            'column': column,
            'severity': 'warning'
        })

class SyntaxValidator:
    """轻量级语法验证器"""
    
    def __init__(self, logger=None):
        self.logger = logger

        language_validators = {
            'swift': self._validate_swift_syntax,
            'objc': self._validate_objc_syntax,
            'kotlin': self._validate_kotlin_syntax,
            'java': self._validate_java_syntax,
        }

        self.validators: Dict[str, callable] = {}
        for language, handler in language_validators.items():
            for ext in language_to_extensions(language):
                self.validators[ext] = handler
    
    def validate_file(self, file_path: str, content: str) -> ValidationResult:
        """验证单个文件的语法"""
        result = ValidationResult(
            is_valid=True,
            errors=[],
            warnings=[],
            file_path=file_path
        )
        
        # 获取文件扩展名
        ext = None
        for extension in self.validators.keys():
            if file_path.endswith(extension):
                ext = extension
                break
        
        if not ext:
            result.add_warning(f"未知的文件类型: {file_path}")
            return result
        
        # 基础检查（所有语言通用）
        self._check_basic_syntax(content, result)
        
        # 语言特定检查
        if ext in self.validators:
            self.validators[ext](content, result)
        
        if self.logger and not result.is_valid:
            self.logger.log_warning(f"语法验证失败: {file_path}, 错误数: {len(result.errors)}")
        
        return result
    
    def _check_basic_syntax(self, content: str, result: ValidationResult):
        """基础语法检查（所有语言通用）"""
        
        # 1. 检查括号平衡
        brackets = {'(': ')', '[': ']', '{': '}'}
        stack = []
        lines = content.split('\n')
        
        for line_num, line in enumerate(lines, 1):
            # 跳过注释和字符串
            cleaned_line = self._remove_strings_and_comments(line)
            
            for col_num, char in enumerate(cleaned_line, 1):
                if char in brackets.keys():
                    stack.append((char, line_num, col_num))
                elif char in brackets.values():
                    if not stack:
                        result.add_error(f"未匹配的闭括号 '{char}'", line_num, col_num)
                    else:
                        open_bracket, _, _ = stack[-1]
                        if brackets[open_bracket] == char:
                            stack.pop()
                        else:
                            result.add_error(
                                f"括号不匹配: 期望 '{brackets[open_bracket]}', 得到 '{char}'",
                                line_num, col_num
                            )
        
        # 检查未闭合的括号
        for open_bracket, line_num, col_num in stack:
            result.add_error(f"未闭合的括号 '{open_bracket}'", line_num, col_num)
        
        # 2. 检查引号平衡
        self._check_quotes_balance(content, result)
        
        # 3. 检查分号（某些语言需要）
        self._check_semicolons(content, result)
    
    def _remove_strings_and_comments(self, line: str) -> str:
        """移除字符串和注释，避免误判"""
        # 移除单行注释
        if '//' in line:
            line = line[:line.index('//')]

        # 移除块注释（同一行）
        line = re.sub(r'/\*.*?\*/', '', line)

        # 更稳健地移除字符串，处理转义字符
        line = re.sub(r'"(?:\\.|[^"\\])*"', '', line)
        line = re.sub(r"'(?:\\.|[^'\\])*'", '', line)

        return line
    
    def _check_quotes_balance(self, content: str, result: ValidationResult):
        """检查引号平衡"""
        lines = content.split('\n')

        in_triple_double = False
        in_triple_single = False
        in_block_comment = False

        for line_num, line in enumerate(lines, 1):
            working_line = line

            if in_block_comment:
                if '*/' in working_line:
                    working_line = working_line.split('*/', 1)[1]
                    in_block_comment = False
                else:
                    continue

            if '/*' in working_line:
                before, _, after = working_line.partition('/*')
                if '*/' in after:
                    after = after.split('*/', 1)[1]
                    working_line = before + after
                else:
                    working_line = before
                    in_block_comment = True

            stripped = working_line.strip()
            if stripped.startswith('//') or stripped.startswith('#'):
                continue

            # 检测多行字符串边界
            scan_index = 0
            while scan_index < len(working_line):
                segment = working_line[scan_index:scan_index+3]
                if segment == '"""':
                    in_triple_double = not in_triple_double
                    scan_index += 3
                    continue
                if segment == "'''":
                    in_triple_single = not in_triple_single
                    scan_index += 3
                    continue
                scan_index += 1

            # 多行字符串内部跳过逐行引号检测
            if in_triple_double or in_triple_single:
                continue

            # 检查双引号
            double_quotes = 0
            escaped = False
            for char in working_line:
                if char == '\\':
                    escaped = not escaped
                elif char == '"' and not escaped:
                    double_quotes += 1
                elif char != '\\':
                    escaped = False

            if double_quotes % 2 != 0:
                result.add_error("未闭合的双引号", line_num)

            # 检查单引号
            single_quotes = 0
            escaped = False
            for char in working_line:
                if char == '\\':
                    escaped = not escaped
                elif char == "'" and not escaped:
                    single_quotes += 1
                elif char != '\\':
                    escaped = False

            if single_quotes % 2 != 0:
                result.add_error("未闭合的单引号", line_num)
    
    def _check_semicolons(self, content: str, result: ValidationResult):
        """检查分号（仅对需要分号的语言）"""
        # 这个会在语言特定的验证器中处理
        pass
    
    def _validate_swift_syntax(self, content: str, result: ValidationResult):
        """Swift特定语法检查"""
        lines = content.split('\n')
        
        for line_num, line in enumerate(lines, 1):
            stripped = line.strip()
            
            # 检查关键字使用
            if stripped.startswith('class ') or stripped.startswith('struct ') or \
               stripped.startswith('enum ') or stripped.startswith('protocol '):
                # 检查类名是否为空
                parts = stripped.split()
                if len(parts) < 2:
                    result.add_error(f"类型声明缺少名称", line_num)
            
            # 检查函数声明
            if 'func ' in stripped:
                # 确保有函数名和括号
                if not re.search(r'func\s+\w+\s*\(', stripped):
                    result.add_error(f"函数声明格式错误", line_num)
            
            # 检查变量声明
            if stripped.startswith('var ') or stripped.startswith('let '):
                # 确保有变量名
                parts = stripped.split()
                if len(parts) < 2:
                    result.add_error(f"变量声明缺少名称", line_num)
            
            # 检查可选链
            if '?.' in stripped or '!.' in stripped:
                # 确保前后都有内容
                if stripped.startswith('?.') or stripped.startswith('!.'):
                    result.add_error(f"可选链操作符使用错误", line_num)
    
    def _validate_objc_syntax(self, content: str, result: ValidationResult):
        """Objective-C特定语法检查"""
        lines = content.split('\n')
        
        # 检查 @interface/@implementation 配对
        interface_count = 0
        implementation_count = 0
        
        for line_num, line in enumerate(lines, 1):
            stripped = line.strip()
            
            if stripped.startswith('@interface'):
                interface_count += 1
            elif stripped.startswith('@implementation'):
                implementation_count += 1
            elif stripped.startswith('@end'):
                # @end 应该配对
                pass
            
            # 检查方法声明
            if stripped.startswith('-') or stripped.startswith('+'):
                # 确保有返回类型和方法名
                if not re.search(r'^[+-]\s*\([^)]+\)\s*\w+', stripped):
                    result.add_warning(f"方法声明可能有误", line_num)
            
            # 检查属性声明
            if '@property' in stripped:
                # 确保有类型和名称
                if not re.search(r'@property\s*\([^)]*\)\s*\w+\s*\*?\s*\w+', stripped):
                    result.add_warning(f"属性声明可能有误", line_num)
            
            # 检查分号（ObjC需要分号）
            if stripped and not stripped.startswith('//') and not stripped.startswith('#'):
                if not stripped.endswith((';', '{', '}', ':')):
                    # 某些语句需要分号
                    if any(kw in stripped for kw in ['return', 'break', 'continue', '=', '++', '--']):
                        if not stripped.endswith(';'):
                            result.add_warning(f"语句可能缺少分号", line_num)
    
    def _validate_kotlin_syntax(self, content: str, result: ValidationResult):
        """Kotlin特定语法检查"""
        lines = content.split('\n')
        
        for line_num, line in enumerate(lines, 1):
            stripped = line.strip()
            
            # 检查类声明
            if any(stripped.startswith(kw + ' ') for kw in ['class', 'data class', 'interface', 'object']):
                # 确保有类名
                if not re.search(r'(class|interface|object)\s+\w+', stripped):
                    result.add_error(f"类型声明缺少名称", line_num)
            
            # 检查函数声明
            if 'fun ' in stripped:
                # 确保有函数名
                if not re.search(r'fun\s+\w+\s*\(', stripped):
                    result.add_error(f"函数声明格式错误", line_num)
            
            # 检查变量声明
            if stripped.startswith('val ') or stripped.startswith('var '):
                # 确保有变量名
                parts = stripped.split()
                if len(parts) < 2:
                    result.add_error(f"变量声明缺少名称", line_num)
            
            # 检查空安全操作符
            if '?.' in stripped or '!!' in stripped:
                # 确保使用正确
                if stripped.startswith('?.') or stripped.startswith('!!'):
                    result.add_error(f"空安全操作符使用错误", line_num)
            
            # 检查Lambda表达式（避免误判类型声明）
            line_no_str = self._remove_strings_and_comments(line)
            if '->' in line_no_str:
                if '{' in line_no_str or '}' in line_no_str:
                    continue
                if re.search(r':\s*[^=]*->', line_no_str):
                    continue
                if re.search(r'fun\s+\w+\s*\([^)]*\)\s*:\s*[^=]*->', line_no_str):
                    continue
                if re.search(r'\([^)]*\)\s*->\s*\w', line_no_str):
                    continue
                result.add_warning(f"Lambda表达式格式可能有误", line_num)
    
    def _validate_java_syntax(self, content: str, result: ValidationResult):
        """Java特定语法检查"""
        lines = content.split('\n')
        
        for line_num, line in enumerate(lines, 1):
            stripped = line.strip()
            
            # 检查类声明
            if any(stripped.startswith(kw + ' ') for kw in ['class', 'interface', 'enum']):
                # 确保有类名
                if not re.search(r'(class|interface|enum)\s+\w+', stripped):
                    result.add_error(f"类型声明缺少名称", line_num)
            
            # 检查方法声明
            if re.search(r'(public|private|protected|static|final|void|int|String|boolean|double|float|long)\s+\w+\s*\(', stripped):
                # 基本方法格式检查通过
                pass
            
            # 检查分号（Java需要分号）
            if stripped and not stripped.startswith('//') and not stripped.startswith('/*'):
                if not stripped.endswith((';', '{', '}', ',')):
                    # 某些语句需要分号
                    keywords_need_semicolon = ['return', 'break', 'continue', 'throw']
                    if any(stripped.startswith(kw) for kw in keywords_need_semicolon):
                        result.add_error(f"语句缺少分号", line_num)
                    elif '=' in stripped and not '{' in stripped:
                        result.add_warning(f"赋值语句可能缺少分号", line_num)
            
            # 检查注解
            if stripped.startswith('@'):
                # 确保注解格式正确
                if not re.search(r'@\w+(\([^)]*\))?', stripped):
                    result.add_warning(f"注解格式可能有误", line_num)
    
    def validate_changes(self, original: str, obfuscated: str, file_path: str) -> ValidationResult:
        """验证混淆前后的变化是否合理"""
        result = self.validate_file(file_path, obfuscated)
        
        # 额外检查：确保结构没有被破坏
        original_lines = len(original.split('\n'))
        obfuscated_lines = len(obfuscated.split('\n'))
        
        if abs(original_lines - obfuscated_lines) > 10:
            result.add_warning(f"行数变化较大: {original_lines} -> {obfuscated_lines}")
        
        # 检查关键结构是否保留
        original_classes = len(re.findall(r'\bclass\s+\w+', original))
        obfuscated_classes = len(re.findall(r'\bclass\s+\w+', obfuscated))
        
        if original_classes != obfuscated_classes:
            result.add_warning(f"类数量变化: {original_classes} -> {obfuscated_classes}")
        
        return result
